﻿using Pap.Core.Utilities;

namespace Pap.Web.Modules.Administration.Views
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Web.UI;
    using Coolite.Ext.Web;
    using global::Utils.UIPermission;
    using Pap.Data;
    using Pap.Web.Modules.Administration.ViewModel;
    using Pap.Web.Utils;

    /// <summary>
    /// The Settings page
    /// </summary>
    public partial class Settings : BasePage<SettingsViewModel>, IPermittedPage
    {
        /// <summary>
        /// Gets the current committee ID.
        /// </summary>
        /// <value>
        /// The current committee ID.
        /// </value>
        public Guid CurrentCommitteeID
        {
            get
            {
                return RegistryInfo.CommitteeID;
            }
        }

        /// <summary>
        /// Handles the Load event of the Page control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Ext.IsAjaxRequest)
            {
                if (!Page.IsPostBack)
                {
                    //IEnumerable<ICommittee> committeesArr = this.ViewModel.GetAllCommittees();
                    //if (committeesArr.Count() == 1 & CurrentCommitteeID.IsNullOrEmpty())
                    //{
                    //    RedirectToCommitteeSettingsPage(committeesArr.First().CommitteeID.ToString(), committeesArr.First().CommitteeName);
                    //}

                    //this.committeesStore.DataSource = committeesArr;
                    //this.committeesStore.DataBind();

                    if (CurrentCommitteeID != null)
                    {
                        //this.comboCommittees.SelectedItem.Value = CurrentCommitteeID.ToString();
                        try
                        {
                            IEnumerable<ISettingCategory> categories = this.ViewModel.GetSettings(CurrentCommitteeID.ToString());
                            foreach (var cat in categories)
                            {
                                var localResourceString = GetLocalResourceObject(cat.Name).ToString();
                                Tab catTab = new Tab { Title = localResourceString };
                                PropertyGrid propGrid = GetSettingsGrid(cat.Settings);

                                //Disable Sorting
                                propGrid.Listeners.Render.Handler = "this.getStore().sortInfo = undefined;";

                                catTab.BodyControls.Add(EncloseInFitLayout(propGrid));

                                tabPanelCategories.Tabs.Add(catTab);
                            }
                        }
                        catch
                        {
                            Ext.Msg.Configure(new MessageBox.Config
                            {
                                Title = this.GetLocalResourceObject("ErrorCaption").ToString(),
                                Message = this.GetLocalResourceObject("CouldntLoadSettings").ToString(),
                                Buttons = MessageBox.Button.OK,
                                Icon = MessageBox.Icon.ERROR
                            }).Show();
                        }
                    }
                    else
                    {
                        tabPanelCategories.Hide();
                    }
                }
            }
        }

        /// <summary>
        /// Encloses the component in fit layout.
        /// </summary>
        /// <param name="catTab">The component.</param>
        /// <returns></returns>
        private FitLayout EncloseInFitLayout(Component catTab)
        {
            FitLayout fit = new FitLayout();
            fit.Items.Add(catTab);
            return fit;
        }

        /// <summary>
        /// Gets the settings grid.
        /// </summary>
        /// <param name="settings">The settings.</param>
        /// <returns></returns>
        private PropertyGrid GetSettingsGrid(List<ISetting> settings)
        {
            PropertyGrid propGrid = new PropertyGrid();
            //propGrid.ID = "propGrid";
            //propGrid.IDMode = IDMode.Static;

            foreach (var setting in settings)
            {
                var localResourceString = GetLocalResourceObject(setting.Label).ToString();
                PropertyGridParameter prop = new PropertyGridParameter(localResourceString, setting.Value);

                Field editorField = GetInitializedEditorField(setting.EditorType, setting.EditorParams);
                if (editorField != null)
                {

                    prop.Editor.Add(editorField);
                }

                propGrid.Source.Add(prop);
            }
            propGrid.Listeners.PropertyChange.Fn = "handleChange";
            return propGrid;
        }

        /// <summary>
        /// Gets the initialized editor field.
        /// </summary>
        /// <param name="type">The type of the field to initialize.</param>
        /// <param name="typeParams">The type params.</param>
        /// <returns></returns>
        private Field GetInitializedEditorField(string type, Dictionary<string, string> typeParams)
        {
            if (type.IsNullOrEmpty())
                return null;

            Type fldType = Type.GetType(type, true, true);
            Field fld = (Field)Activator.CreateInstance(fldType);
            foreach (var param in typeParams)
            {
                PropertyInfo paramProperty = fldType.GetProperty(param.Key);
                object propertyValue = ConvertParamValueToPropertyType(param.Value, paramProperty.PropertyType);
                paramProperty.SetValue(fld, propertyValue, null);
            }
            return fld;
        }

        /// <summary>
        /// Converts the value to the destination property type.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="destinationType">Type of the destination.</param>
        /// <returns></returns>
        private object ConvertParamValueToPropertyType(string value, Type destinationType)
        {

            if (destinationType == typeof(string))
            {
                return value;
            }
            else if (destinationType.IsEnum)
            {
                return Enum.Parse(destinationType, value);
            }
            else if (destinationType == typeof(int))
            {
                return (int.Parse(value));
            }
            else if (destinationType == typeof(float))
            {
                return (float.Parse(value));
            }
            else if (destinationType == typeof(double))
            {
                return (double.Parse(value));
            }
            else if (destinationType == typeof(decimal))
            {
                return (decimal.Parse(value));
            }
            else if (destinationType == typeof(DateTime))
            {
                return (DateTime.Parse(value));
            }
            else
            {
                string expMessage = (string)this.GetLocalResourceObject("UnsupportedTypeException");
                throw new Exception(expMessage);
            }
        }

        /// <summary>
        /// Saves the settings.
        /// </summary>
        /// <param name="strChanges">JSON object containing changes.</param>
        [AjaxMethod]
        public void saveSettings(string strChanges)
        {
            Newtonsoft.Json.Linq.JArray jarrChanges = (Newtonsoft.Json.Linq.JArray)JSON.Deserialize(strChanges);
            var changedSettings = (from item in jarrChanges
                                   select new
                                   {
                                       label = item["label"].ToString().Trim('"'),
                                       value = item["value"].ToString().Trim('"')
                                   }).ToArray();

            List<string> labels = new List<string>();
            List<string> values = new List<string>();

            IEnumerable<ISettingCategory> categories = this.ViewModel.GetSettings(CurrentCommitteeID.ToString());
            foreach (var setting in changedSettings)
            {
                if (UICulture == "English (United States)")
                {
                    labels.Add(setting.label);
                    values.Add(setting.value);
                }
                else
                {
                    foreach (var cat in categories)
                    {
                        foreach (var catSetting in cat.Settings)
                        {
                            string settingName = GetLocalResourceObject(catSetting.Key).ToString();
                            if (setting.label == settingName)
                            {
                                labels.Add(catSetting.Key);
                                break;
                            }
                        }
                    }
                    values.Add(setting.value);
                }
            }
            try
            {
                this.ViewModel.SaveSettings(CurrentCommitteeID.ToString(), labels.ToArray(), values.ToArray());
                string savingDoneMsg = (string)this.GetLocalResourceObject("savingDoneMsg");
                Ext.Redirect("~", savingDoneMsg);
            }
            catch (Exception exp)
            {
                string notSavedTitle = (string)this.GetLocalResourceObject("notSavedTitle ");
                string notSavedBody;
                if (exp is ArgumentException)
                {
                    notSavedBody = (string)this.GetLocalResourceObject("InvalidValueException") + (exp as ArgumentException).ParamName;
                }
                else
                {
                    notSavedBody = exp.Message;
                }

                Ext.MessageBox.Configure(new MessageBox.Config
                {
                    Title = notSavedTitle,
                    Message = notSavedBody,
                    Buttons = MessageBox.Button.OK,
                    Icon = MessageBox.Icon.ERROR
                }).Show();
            }
        }

        /// <summary>
        /// Handles the select event for the combobox
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="Coolite.Ext.Web.AjaxEventArgs"/> instance containing the event data.</param>
        /*  public void comboItemSelected(object sender, AjaxEventArgs e)
          {
              RedirectToCommitteeSettingsPage(comboCommittees.SelectedItem.Value, comboCommittees.SelectedItem.Text);
          }   */

        /// <summary>
        /// Redirects to committee settings page.
        /// </summary>
        /// <param name="committeeID">The committee ID.</param>
        /// <param name="committeeName">Name of the committee.</param>
        private void RedirectToCommitteeSettingsPage(string committeeID, string committeeName)
        {
            string resLoadSettings = (string)this.GetLocalResourceObject("LoadCommitteeSettingsMessage");
            Ext.Redirect("~/administration.route/settings?CommitteeID=" + committeeID, resLoadSettings + committeeName + "...");
        }

        #region IPermittedPage Members

        /// <summary>
        /// Gets the name of the permission.
        /// </summary>
        /// <value>
        /// The name of the permission.
        /// </value>
        public string PermissionName
        {
            get { return "Settings"; }
        }

        #endregion
    }
}
